using System;
using System.Data;
using System.Xml;

using OR.Reuse.Persistence;

using OR.Lazarus.Config;

namespace OR.Lazarus.Library.DataTier.Source
{
    public class MethodDetail : OR.Lazarus.Library.DataTier.Source.Lazarus.MethodDetail
    {
        private FieldCollection mAffectedFields;
        private bool mReturnResultSet;

        public FieldCollection AffectedFields
        {
            get { return mAffectedFields; }
            set { mAffectedFields = value; }
        }

        public bool ReturnResultSet
        {
            get { return mReturnResultSet; }
            set { mReturnResultSet = value; }
        }

        public bool CustomFields
        {
            get { return (mAffectedFields.Count != 0); }
        }

        public bool CustomObjects
        {
            get { return (mAffectedObjects.Count != 0); }
        }

        public bool CustomParams
        {
            get { return (mParameters.Count != 0); }
        }

        public bool CustomFilters
        {
            get { return (mFilters.Count != 0); }
        }

        public bool IsCustom
        {
            get { return (CustomFields || CustomObjects || CustomParams || CustomFilters); }
        }

        public ObjectDetail ParentObject
        {
            get
            {
                return (this.GetParentEntity());
            }
            set
            {
                base.ParentEntity = value;
            }
        }

        protected virtual ObjectDetail GetParentEntity()
        {
            ObjectDetail vReturn = null;

            if (base.ParentEntity is ObjectDetail)
            {
                vReturn = (ObjectDetail)base.ParentEntity;
            }

            return (vReturn);
        }

        public MethodDetail()
        {
            mAffectedFields = new FieldCollection();
        }

        public void Initialize()
        {
            this.OnInitialize();
            this.OnValidate();
        }

        public override void LoadXml(XmlElement pSource)
        {
            base.LoadXml(pSource);

            mReturnResultSet = DataUtility.GetBool(pSource, "return-result", false);

            XmlElement vAffectedFields = (XmlElement)pSource.SelectSingleNode("lz:affected-fields", PersistenceConfig.Namespaces);

            if (vAffectedFields != null)
            {
                mAffectedFields.LoadXml(vAffectedFields);
            }
        }

        public override XmlElement SaveXml(XmlDocument p_docContext)
        {
            XmlElement vReturn = base.SaveXml(p_docContext);

            vReturn.SetAttribute("return-result", mReturnResultSet.ToString());

            XmlElement vCollection = null;

            vCollection = mAffectedFields.SaveXml(p_docContext);

            if (vCollection != null)
            {
                vReturn.AppendChild(vCollection);
            }

            return (vReturn);
        }

        protected virtual void OnInitialize()
        {
            if (String.IsNullOrEmpty(this.Name))
            {
                this.Name = this.MethodType;
            }

            if (String.IsNullOrEmpty(this.ObjectName))
            {
                this.ObjectName = this.Name;
            }

            if (String.IsNullOrEmpty(this.DBName))
            {
                if (this.ParentObject == null)
                {
                    this.DBName = this.ObjectName;
                }
                else
                {
                    this.DBName = this.ParentObject.Name + this.ObjectName;
                }
            }

            if (String.IsNullOrEmpty(this.Description))
            {
                this.Description = this.GetDescription();
            }

            foreach (FilterDetail vFilter in this.Filters)
            {
                vFilter.Initialize();
            }
        }

        protected virtual void OnValidate()
        {
            if (this.IsCustom)
            {
                if (!CustomFilters && this.MethodType == CompilerSettings.METHODTYPE_UPDATE)
                {
                    throw new ApplicationException(String.Format("OnValidate for Method {0}.{1} failed: For data integrity purposes, filterless updates are not supported.", this.ParentObject.Name, this.Name));
                }
            }
        }

        public string GetDescription()
        {
            string rtnVal = this.Description;

            if (String.IsNullOrEmpty(rtnVal))
            {
                switch (this.MethodType)
                {
                    case CompilerSettings.METHODTYPE_CREATE:
                        {
                            rtnVal = String.Format("Creates a new {0}.", this.ParentObject.FriendlyName);

                            break;
                        }
                    case CompilerSettings.METHODTYPE_UPDATE:
                        {
                            rtnVal = String.Format("Updates an existing {0} matching the specified ID.", this.ParentObject.FriendlyName);

                            break;
                        }
                    case CompilerSettings.METHODTYPE_GET:
                        {
                            rtnVal = String.Format("Returns a single {0} matching the specified ID.", this.ParentObject.FriendlyName);

                            break;
                        }
                    case CompilerSettings.METHODTYPE_LIST:
                        {
                            rtnVal = String.Format("Returns a list of {0} records.", this.ParentObject.FriendlyName);

                            int filterCount = this.Filters.Count;

                            if (filterCount > 0)
                            {
                                rtnVal += "  This list is filtered by the supplied ";

                                for (int i = 0; i < filterCount; i++)
                                {
                                    FilterDetail currentFilter = this.Filters[i];

                                    if ((filterCount > 1) && (i == (filterCount - 1)))
                                    {
                                        rtnVal += " and ";
                                    }

                                    rtnVal += currentFilter.Param;

                                    if (i < (filterCount - 1))
                                    {
                                        rtnVal += ", ";
                                    }
                                    else
                                    {
                                        rtnVal += ".";
                                    }
                                }
                            }

                            break;
                        }
                }
            }

            return rtnVal;
        }
    }
}
